///#######################################################################
///#      plane3d.lua - class that implements a 3d Plane.
///#######################################################################
///#      Autor - AMiranda, June/2009 (get from cgcPlane)
///#######################################################################


#ifndef _PLANE_3D_
#define _PLANE_3D_

#include <iostream>
#include <math.h>
#include "point3d.h"

using namespace std;

///	just a small number used for geometrical operations.
const   double geomLibTOLERANCE = 1.0e-06;


//
//////////////////////////////////////////////////////////////////////////
class Plane3D
{
public:
  /** default constructor. */
  Plane3D(void) : d(0.0) { }

  /** creates a plane given by three noncolinear points. <br>
  * 
  * Parametric form: p = origin + u*t1 + v*t2, where origin = pt0, 
  * u is a unity vector with direction <br> pt1 - pt0, 
  * and v is a unity vector, on the plane, perpendicular to u. <br>
  * 
  * Implicit form: normal . (x,y,z) + d = 0, where 
  *    normal = (u X v), and d = -normal.origin.
  * 
  * @param pt0 first point.
  * @param pt1 second point.
  * @param pt2 third point.
  */
  Plane3D ( const Point3D& pt0, const Point3D &pt1, const Point3D& pt2 );

  /// constructor from another plane.
  Plane3D ( const Plane3D& p ) { *this = p; }

  /**
  * creates a plane given by its normal and a point on it. <br>
  * Parametric form: p = origin + u*t1 + v*t2. <br>
  * Implicit form: normal . (x,y,z) + d = 0, where d = -normal . origin.
  * @param origin a point on the plane.
  * @param normal plane normal.
  */
  Plane3D ( const Point3D& origin, const Point3D &normal );


  /**  sets the plane origin.
  * 
  * @param o plane origin.
  */
  void  setOrigin ( const Point3D& o );


  /**  sets the plane normal.
  * 
  * @param n plane normal.
  */
  void  setNormal ( const Point3D& n );

  /**  returns the plane origin.
  * 
  * @return plane origin.
  */
  Point3D getOrigin ( ) const;

  /**  returns the plane normal.
  * 
  * @return plane normal.
  */
  Point3D getNormal ( ) const;

  /**  gets a right handed local coordinate system for this plane.
  * 
  * @param u unity vector parallel to the first axis.
  * @param v unity vector parallel to the second axis.
  * @param n unity vector parallel to the third axis (the normal vector).
  * @param o system origin (the plane origin).
  */
  void  getLocalCoordinateSystem ( Point3D& u, Point3D& v, 
    Point3D& n, Point3D& o ) const;

  ///  copy operator.
  Plane3D& operator = ( const Plane3D& p );

  /**  inversion operator. 
  * Creates a new plane with opposite normal direction of this plane.
  */
  Plane3D operator - ( ) const;

  // ---------------- print stuff  -------------------------

  /// chaining method to print an object's instance variables.
  virtual void print(ostream& os, const char* sthing) const;


  /**
  * computes the Cartesian coordinates of the closest
  * point on a plane, to a given point. It is used the plane implicit
  * form.
  * 
  * @param pt given point.
  * @param clst closest point on the plane.
  */
  void  clstPoint ( const Point3D& pt, Point3D& clst ) const;

  Point3D clstPoint ( const Point3D& pt ) const;

  /**
  * computes the cartesian coordinates of the closest point on a plane,
  * to a given  point.
  * It is used the plane normalized parametric form.
  * 
  * @param pt given point.
  * @param clst closest point.
  */
  void  clstPointNorm ( const Point3D& pt, Point3D& clst ) const;

  /**
  * returns the signed distance between a point and a
  * plane. The sign is positive if the point is in the half space
  * pointed to by the plane normal, and negative otherwise. <br>
  * 
  * |-> * ( + ) and <-| * ( - )
  * 
  * @param pt given point.
  * @return the signed distance between a point and a plane.
  * 
  */
  double  distanceToPoint  ( const Point3D& pt ) const;

  /**
  * computes the intersection of this and a given plane.
  *
  * @param pln given plane.
  * @param ln intersection line.
  * @param tol tolerance for deciding parallelism. 
  * @return if the two planes intersect, and 0 otherwise.
  *
  */
  //int  intersect ( const cgcPlane&  pln, cgcLine& ln, 
  //  double tol = cgcTOLERANCE ) const;

  /**
  * generates the cartesian point corresponding to the evaluation 
  * of two parametric values (u and v) of a plane given in a parametric 
  *    form.
  * 
  * @param u first parametric value.
  * @param v second parametric value.
  * @param pt evaluated cartesian point.
  */
  void  eval ( double u, double v, Point3D& pt ) const;

  Point3D eval ( double u, double v ) const;


  /** reinitializes a plane. 
  * 
  * @param origin plane origin.
  * @param normal plane normal.
  */
  void  rebind ( const Point3D& origin, const Point3D& normal );


  ~Plane3D(void);

private:

  /// A vector on the plane.
  Point3D m_u; 
  /// A vector on the plane.
  Point3D m_v;  
  ///  The normal vector of the plane.
  Point3D m_normal; 
  /// A point on the plane.
  Point3D m_origin;  
  ///  The number d of the equation: ax+by+cz+d=0. 
  double d;  

};


/**	
*	returns whether a number is less, equal, or greater than another number. <br>
*	( 0) if a = b (the two numbers are equal, unless a given tolerance),  <br>
*	( 1) if a > b and <br>
*	(-1) if a < b
*	
*	@param a first number to be tested.
*	@param b second number to be tested.
*	@param tol tolerance used for deciding equality.
*	@return -1, 0, 1 whether the first number is less, equal, or greater than the second number.
*/
template <class T> 
inline int geomLibCompare ( const T a, const T b, const T tol )
{ 
  return ( fabs ( a-b ) <= tol ? 0 : a > b ? 1 : -1 ); 
}


#endif
